package com.chuangke.aspect;

import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSONObject;
import com.chuangke.common.http.HttpResult;
import com.chuangke.common.utils.HttpServletRequestUtils;
import com.chuangke.common.utils.HttpUtils;
import com.chuangke.common.utils.IpUtils;
import com.chuangke.system.annotation.ApiLogDoc;
import com.chuangke.system.entity.SysApiLog;
import com.chuangke.system.service.SysApiLogService;

/**
 * 系统日志，切面处理类，记录日志
 */
@Aspect
@Component
public class SysApiLogAspect {

	private static final Logger logger = LoggerFactory.getLogger(SysApiLogAspect.class);

	@Autowired
	private SysApiLogService sysApiLogService;

	@Around("@annotation(com.chuangke.system.annotation.ApiLogDoc)")
	public Object around(ProceedingJoinPoint point) throws Throwable {
		long beginTime = System.currentTimeMillis();
		Object result = null;
		try {
			// 执行方法
			result = point.proceed();
			// 执行时长(毫秒)
			long time = System.currentTimeMillis() - beginTime;
			// 保存日志
			saveSysOptLog(point, time, result, null);
		} catch (Throwable e) {
			// 执行时长(毫秒)
			long time = System.currentTimeMillis() - beginTime;
			// 保存日志
			saveSysOptLog(point, time, null, e);
			throw e;
		}

		return result;
	}

	@Async
	public void saveSysOptLog(ProceedingJoinPoint joinPoint, long time, Object result, Throwable throwable) {
		try {
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			Method method = signature.getMethod();
			ApiLogDoc optLogDoc = method.getAnnotation(ApiLogDoc.class);

			String status = "0";
			if (result instanceof HttpResult) {
				if (((HttpResult) result).getCode() == 200) {
					status = "1";
				}
			}

			// 重汽预算返回接口的返回格式
			if (result != null && "BUDGET_SEND".equals(optLogDoc.apiId())) {
				if ("200".equals(((JSONObject) ((JSONObject) result).get("Responses")).get("RETURN_CODE").toString())) {
					status = "1";
				}
			}

			SysApiLog log = new SysApiLog();

			if (throwable != null) {
				log.setExceptionMsg(ExceptionUtils.getMessage(throwable));
			}

			log.setApiId(optLogDoc.apiId());
			log.setApiName(optLogDoc.apiName());
			log.setCreatedAt(new Date());
			log.setMothodName(joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()");
			log.setReqAddr(HttpServletRequestUtils.getIpAddr(HttpUtils.getHttpServletRequest()));
			log.setReqDate(new Date());
			log.setReqParam(getParams(joinPoint));
			log.setReqType(optLogDoc.reqType());
			log.setResAddr(IpUtils.getHostIp1());
			log.setResCode(status);
			log.setResDate(new Date());
			log.setResParam(JSONObject.toJSONString(result));
			log.setUseTime(time);

			sysApiLogService.saveAsync(log);
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
	}

	private String getParams(ProceedingJoinPoint joinPoint) {
		StringBuilder params = new StringBuilder();
		Object[] args = joinPoint.getArgs();
		for (int i = 0; i < args.length; i++) {
			if (args[i] instanceof HttpServletRequest) {
				continue;
			}

			params.append("Param").append(i).append(":");
			try {
				if (args[i] instanceof MultipartFile) {
					params.append("文件上传");
				} else {
//					SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
//					filter.getExcludes().add("password");
					params.append(JSONObject.toJSONString(args[i]));
				}
			} catch (Exception e) {
				params.append("Parse failured!");
			}
			params.append(" ; ");
		}
//		return params.length() > 5000 ? params.substring(0, 4900) + "..." : params.toString();
		return params.toString() ;
	}

}
